package cn.parus.commons.common.Log.aspect;

import cn.hutool.core.date.DateTime;
import cn.parus.commons.common.Execption.CustomException;
import cn.parus.commons.common.Log.config.LoggingProperties;
import cn.parus.commons.common.Log.dao.Repsitory.LogRepository;
import cn.parus.commons.common.Log.entity.LogInfo;
import cn.parus.commons.common.Log.utils.ServerWebExchangeContext;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;

/**
 * @Title: LogAspect
 * @Author 潘春兰
 * @Package cn.parus.commons.common.Log.aspect
 * @Date 2025/3/28 20:53
 * @description: TODO AOP切面生成日志信息
 * @Version:
 */
@Aspect
@Component
public class LogAspect {
    private final LogRepository logRepository;
    private final LoggingProperties loggingProperties;

    /**
     * TODO 使用构造方法注入，避免循环依赖
     * @param logRepository
     * @param loggingProperties
     */
    @Autowired
    public LogAspect(LogRepository logRepository,LoggingProperties loggingProperties){
        this.logRepository = logRepository;
        this.loggingProperties = loggingProperties;

    }
    /**
     * TODO 定义切点 - 拦截所有Controller方法,并给带有NoLogging注解的方法不记录日志
     */
    @Pointcut("@within(org.springframework.stereotype.Controller) || " +
            "@within(org.springframework.web.bind.annotation.RestController)&&"+
             "!@annotation(cn.parus.commons.common.Log.aspect.NoLogging)")
    public void controllerPointcut() {}

    /**
     * TODO 环绕通知 - 记录方法调用日志
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("controllerPointcut()")
    public Object logApiCall(ProceedingJoinPoint joinPoint) throws Throwable {

        long startTime = System.currentTimeMillis();

        //获取ServerWebExchange对象
        ServerWebExchange exchange = ServerWebExchangeContext.getServerWebExchange();

        // 获取客户端IP地址
        String ipAddr = getClientIp(exchange);

        //生成日志对象
        LogInfo logInfo = new LogInfo();

        logInfo.setClassName(joinPoint.getTarget().getClass().getName());

        logInfo.setMethodName(joinPoint.getSignature().getName());

        logInfo.setParams(Arrays.toString(joinPoint.getArgs()));

        logInfo.setIpAddr(ipAddr);

        try {
            Object result = joinPoint.proceed();
            logInfo.setStatus("success");
            long endTime = System.currentTimeMillis();
            logInfo.setExecutionTime(endTime - startTime);
            logInfo.setCreatedTime(String.valueOf(DateTime.now()));
            //  异步保存日志
            CompletableFuture.runAsync(() -> {
                try {
                    String resultStr = result != null ? result.toString() : "null";
                    if (resultStr.length() > 2000) {
                        resultStr = resultStr.substring(0, 2000) + "...[truncated]";
                    }
                    logInfo.setResult(resultStr);
                    logRepository.save(logInfo);
                    System.out.println("Log saved asynchronously.");
                } catch (Exception e) {
                    System.err.println("Failed to save log: " + e.getMessage());
                }
            });

            //  直接返回原始结果（不等待日志保存完成）
            return result;
        } catch (Exception e) {
            long endTime = System.currentTimeMillis();

            // 记录执行时间
            logInfo.setExecutionTime(endTime - startTime);
            logInfo.setCreatedTime(String.valueOf(DateTime.now()));

            // 如果是自定义异常 (CustomException)，获取自定义的错误消息
            if (e instanceof CustomException) {
                CustomException customException = (CustomException) e;
                System.out.println("一场消息"+customException.getMsg());
                logInfo.setErrorMessage(customException.getMsg());  // 使用自定义异常的消息
            } else {
                // 其他异常，使用默认的异常消息
                logInfo.setErrorMessage(e.getMessage());
            }

            // 设置状态为 ERROR
            logInfo.setStatus("ERROR");

            // 异步保存日志
            CompletableFuture.runAsync(() -> {
                try {
                    logRepository.save(logInfo);
                    System.out.println("Log saved asynchronously.");
                } catch (Exception logSaveException) {
                    System.err.println("Failed to save log: " + logSaveException.getMessage());
                }
            });

            // 抛出原始异常
            throw e;
        }
    }

    /**
     * TODO 获取客户端IP地址（没有获取到，还没找到原因）
     * @param exchange
     * @return
     */
    private String getClientIp(ServerWebExchange exchange) {
        if (exchange == null) return "unknown";

        String ip = exchange.getRequest().getHeaders().getFirst("X-Forwarded-For");
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = exchange.getRequest().getHeaders().getFirst("Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = exchange.getRequest().getHeaders().getFirst("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = exchange.getRequest().getRemoteAddress() != null ?
                    exchange.getRequest().getRemoteAddress().getAddress().getHostAddress() : "unknown";
        }
        return ip;

    }
}
